package so.sao.shop.supplier.service.impl;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import so.sao.shop.supplier.config.Constant;
import so.sao.shop.supplier.dao.NotificationDao;
import so.sao.shop.supplier.dao.PayDao;
import so.sao.shop.supplier.dao.PurchaseDao;
import so.sao.shop.supplier.domain.Notification;
import so.sao.shop.supplier.domain.Purchase;
import so.sao.shop.supplier.pojo.input.AppCommSalesInput;
import so.sao.shop.supplier.pojo.input.PayInput;
import so.sao.shop.supplier.pojo.vo.PurchaseInfoVo;
import so.sao.shop.supplier.pojo.vo.PurchaseItemVo;
import so.sao.shop.supplier.service.PayService;
import so.sao.shop.supplier.service.PurchaseService;
import so.sao.shop.supplier.service.app.impl.AppCommSalesServiceImpl;
import so.sao.shop.supplier.util.MD5Util;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * Created by acer on 2017/8/15.
 */
@Service
public class PayServiceImpl implements PayService {
    @Resource
    private PayDao payDao;
    @Resource
    private NotificationDao notificationDao;
    @Resource
    private PurchaseDao purchaseDao;
    @Resource
    private PurchaseService purchaseService;
    @Resource
    private AppCommSalesServiceImpl appCommSalesService;

    /**
     * 支付回调接口
     *
     * @param payInput 封装了回调参数
     * @return Result 封装了结果
     * @throws Exception 异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updatePurchasePayment(PayInput payInput) throws Exception {
        boolean flagDao = false;
        if (isSign(payInput)) {
            Map<String, Object> map = mergePaymentInfo(payInput);
            flagDao = payDao.updatePaymentByPayId(map);
            new Thread() {
                @Override
                public void run() {
                    // 根据支付id，批量生成订单的二维码
                    try {
                        purchaseService.createReceivingQrcodeByPayId(payInput.getOrderId());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }.start();
            //TODO 为该供应商推送"待发货"消息通知
            sendNotice(payInput);
            //更新商品销量
            List<Purchase> purchaseList = purchaseDao.findByPayId(payInput.getOrderId());
            List<String> orderIds = new ArrayList<>();
            //存储订单ID
            purchaseList.forEach(purchase -> {
                orderIds.add(purchase.getOrderId());
            });
            List<PurchaseItemVo> purchaseItemVoList = purchaseService.findPurchaseItemByIds(orderIds);
            List<AppCommSalesInput> appCommSalesInputs = new ArrayList<>();
            for (PurchaseItemVo purchaseItemVo : purchaseItemVoList){
                AppCommSalesInput appCommSalesInput = new AppCommSalesInput();
                appCommSalesInput.setGoodsId(purchaseItemVo.getGoodsId());
                appCommSalesInput.setGoodsNum(purchaseItemVo.getGoodsNumber());
                appCommSalesInputs.add(appCommSalesInput);
            }
            appCommSalesService.updateSalesNum(appCommSalesInputs);

            //更新实付金额
            Map<String,Object> payAmountMap = getOrderIdAndTotalPrice(purchaseList,payInput);
            payDao.updatePayAmountByOrderId(payAmountMap);
            //存入支付信息到库
            payDao.insertIntoPayInfo(map);
        }
        return flagDao;
    }

    /**
     * 获取每个订单id对应的实付金额
     * @param purchaseList
     * @return
     */
    private Map<String,Object> getOrderIdAndTotalPrice(List<Purchase> purchaseList,PayInput payInput){
        /**
         * 业务逻辑：
         * 1.payID下的所有订单按合计金额从小到大排序；
         * 2.计算支付宝优惠金额；
         * 3.如果payID下有多单，且合计金额不一，则将这个优惠体现在最大金额的订单上，合计金额相等，在最后一单体现；
         * 4.如果payId下有一个订单，则将支付宝回传的实付金额更新入库。
         */
        //对订单排序（按合计金额从小到大）
        Comparator<Purchase> byOrderTotalPrice = Comparator.comparing(Purchase::getOrderTotalPrice);
        List<Purchase> purchaseListSorted = purchaseList.stream().sorted(byOrderTotalPrice).collect(Collectors.toList());
        //计算支付宝优惠金额
        BigDecimal priceDiff = payInput.getOrderPrice().subtract(payInput.getBuyerPayAmount());
        if(purchaseListSorted.size() > 1){
            purchaseListSorted.get(purchaseListSorted.size()-1).
                    setOrderTotalPrice(purchaseListSorted.get(purchaseListSorted.size()-1).getOrderTotalPrice().subtract(priceDiff));
        } else {
            purchaseListSorted.get(0).setOrderTotalPrice(payInput.getBuyerPayAmount());
        }
        Map<String,Object> map = new HashMap<>();
        purchaseListSorted.forEach(purchase -> {
            map.put(purchase.getOrderId(),purchase.getOrderTotalPrice());
        });
        return map;
    }


    /**
     * 支付回调接口(单订单支付)
     *
     * @param payInput 封装了回调参数,orderId为单个订单ID
     * @return Result 封装了结果
     * @throws Exception 异常
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updatePurchasePaymentByOrderId(PayInput payInput) throws Exception {
        boolean flag = false;
        if (isSign(payInput)) {
            Map<String, Object> map = mergePaymentInfo(payInput);
            flag = payDao.updatePaymentByOrderId(map);
            // 根据订单id，成订单的二维码
            purchaseService.createReceivingQrcode(payInput.getOrderId());
            //TODO 为该供应商推送"待发货"消息通知
            String payId = payDao.findPayIdByOrderId(payInput.getOrderId());
            payInput.setOrderId(payId);
            sendNotice(payInput);
        }
        return flag;
    }

    /**
     * 根据支付ID获取支付总金额
     *
     * @param payId 合并支付ID
     * @return
     */
    @Override
    public BigDecimal getPayOrderTotalPriceByPayId(String payId) {
        return payDao.findPayOrderTotalPrice(payId);
    }

    //判断支付平台传来的串是否合法
    public boolean isSign(PayInput payInput) {
        //拼接订单ID、实付金额、支付流水号字符串
        String str = "orderId=" + payInput.getOrderId() + "&orderPrice=" + payInput.getOrderPrice() + "&orderPaymentNum=" + payInput.getOrderPaymentNum();
        //加密后的订单ID、实付金额、支付流水号字符串
        String md5Str = MD5Util.getMD5(str);
        if (payInput.getSign().equals(md5Str)) {
            return true;
        }
        return false;
    }

    /**
     * 发送消息
     *
     * @param payInput
     */
    private void sendNotice(PayInput payInput) {
        List<Purchase> purchaseList = purchaseDao.findByPayId(payInput.getOrderId());
        List<Notification> notificationList = new ArrayList<>();

        if (null != purchaseList && purchaseList.size() > 0) {
            purchaseList.forEach(purchase -> {
                if (purchase.getPayStatus() != 0) {
                    Notification notification = new Notification(purchase.getStoreId(), 0, purchase.getOrderId(),
                            Constant.NotifiConfig.PENDING_SHIP_NOTIFI + purchase.getOrderId(), new Date(), 0);
                    notificationList.add(notification);
                }
            });
            if (null != notificationList && notificationList.size() > 0) {
                notificationDao.saveNotifications(notificationList);
            }
        }
    }

    /**
     * 合并入参
     *
     * @param payInput 封装了支付回参信息
     * @return Map 封装了入参信息
     */
    private Map<String, Object> mergePaymentInfo(PayInput payInput){
        Map<String, Object> map = new HashMap<>();
        //支付时间
        map.put("orderPaymentTime", payInput.getGmtPayment());
        //更新时间
        map.put("updatedAt", new Date());
        //订单状态
        map.put("orderStatus", Constant.OrderStatusConfig.PENDING_SHIP);
        //订单编号
        map.put("orderId", payInput.getOrderId());
        //支付流水号
        map.put("orderPaymentNum", payInput.getOrderPaymentNum());
        //支付方式
        map.put("orderPaymentMethod", payInput.getOrderPaymentMethod());
        //支付状态  0.未支付状态  1.已支付状态
        map.put("payStatus", 1);
        //交易状态
        map.put("tradeStatus",payInput.getTradeStatus());
        //订单金额
        map.put("orderPrice",payInput.getOrderPrice());
        //商家实收金额
        map.put("receiptAmount",payInput.getReceiptAmount());
        //支付的金额
        map.put("buyerPayAmount",payInput.getBuyerPayAmount());
        //订单标题
        map.put("subject",payInput.getSubject());
        //支付创建的时间
        map.put("payTimeCreate",payInput.getGmtCreate());
        //交易类型
        map.put("businessType",0);
        return map;
    }

}
